package com.kly.order.serviceImpl;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.lang.Snowflake;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSONObject;
import com.fqgj.common.api.Response;
import com.fqgj.common.utils.CollectionUtils;
import com.fqgj.common.utils.DateUtil;
import com.fqgj.common.utils.StringUtils;
import com.kly.dto.AddOrderReq;
import com.kly.dto.ProductDto;
import com.kly.dto.TOrderDto;
import com.kly.enums.*;
import com.kly.order.ServiceUtils;
import com.kly.order.db.dao.ProductDao;
import com.kly.order.db.dao.TOrderDao;
import com.kly.order.db.dao.TOrderLogDao;
import com.kly.order.db.entity.ProductEntity;
import com.kly.order.db.entity.TOrderEntity;
import com.kly.order.db.entity.TOrderLogEntity;
import com.kly.order.mapper.TOrderMapper;
import com.kly.pay.service.impl.GoogleSubScriptionsBasicPayImpl;
import com.kly.req.RepayRequest;
import com.kly.service.TOrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

@Slf4j
@Service("tOrderService")
public class TOrderServiceImpl implements TOrderService {

    @Resource
    TOrderDao tOrderDao;
    @Resource
    TOrderLogDao orderLogDao;
    @Resource
    TOrderMapper mapper;

    @Override
    public Response<List<TOrderDto>> queryOrder(String userCode) {
        Map<String, Object> params = ServiceUtils.getParams();
        params.put("userCode", userCode);
        List<TOrderEntity> tOrderEntities = tOrderDao.selectByParams(params);
        if (tOrderEntities == null || tOrderEntities.isEmpty()) {
            return Response.ok();
        }
        List<TOrderDto> orderDtoList = tOrderEntities.stream().map(mapper::toDto).collect(Collectors.toList());
        return Response.ok(orderDtoList);
    }

    @Override
    public Response<List<TOrderDto>> queryOrderByPurchaseToken(String purchaseToken, String appCode) {
        final List<TOrderEntity> tOrderEntities = tOrderDao.selectByToken(purchaseToken, appCode);

        if (tOrderEntities == null || tOrderEntities.isEmpty()) {
            return Response.ok();
        }

        List<TOrderDto> orderDtoList = tOrderEntities.stream().map(mapper::toDto).collect(Collectors.toList());
        return Response.ok(orderDtoList);
    }

    @Override
    public Response<TOrderDto> queryLatestOrderByPurchaseToken(String purchaseToken, String appCode) {
        if (StringUtils.isEmpty(purchaseToken)) {
            return Response.ok();
        }
        final List<TOrderEntity> orderEntities = tOrderDao.selectByToken(purchaseToken, appCode);
        if (CollectionUtils.isEmpty(orderEntities)) {
            return Response.ok();
        }
        return Response.ok(mapper.toDto(orderEntities.get(0)));
    }

    @Override
    public Response<TOrderDto> queryLatestSubscriptionsOrderByUserCode(String userCode) {
        if (StringUtils.isEmpty(userCode)) {
            return Response.ok();
        }
        final TOrderEntity entity = tOrderDao.queryLatestSubscriptionsOrderByUserCode(userCode);
        if (Objects.isNull(entity)) {
            return Response.ok();
        }
        return Response.ok(mapper.toDto(entity));
    }

    @Override
    public Response<TOrderDto> queryOrderByOrderNo(String orderNo) {
        if (StringUtils.isEmpty(orderNo)) {
            return Response.ok();
        }
        Map<String, Object> params = ServiceUtils.getParams();
        params.put("orderNo", orderNo);
        params.put("deleted", 0);
        final List<TOrderEntity> orderList = tOrderDao.selectByParams(params);
        if (CollectionUtils.isEmpty(orderList)) {
            return Response.ok();
        }
        final TOrderEntity tOrderEntity = orderList.get(0);
        TOrderDto orderDto = new TOrderDto();

//        final TOrderDto orderDto = mapper.toDto(tOrderEntity);
//        orderDto.setBenefitsStatus(tOrderEntity.getBenefitsStatus());

        BeanUtils.copyProperties(tOrderEntity, orderDto);
        log.info("queryOrderByOrderNoResult:{}", JSONObject.toJSONString(orderDto));
        return Response.ok(orderDto);
    }

    @Override
    public Response<TOrderDto> queryOrderByOrderNo2(String orderNo) {
        if (StringUtils.isEmpty(orderNo)) {
            return Response.ok();
        }
        Map<String, Object> params = ServiceUtils.getParams();
        params.put("orderNo", orderNo);
        params.put("deleted", 0);
        final List<TOrderEntity> orderList = tOrderDao.selectByParams(params);
        if (CollectionUtils.isEmpty(orderList)) {
            return Response.ok();
        }
        final TOrderEntity tOrderEntity = orderList.get(0);
        final TOrderDto orderDto = mapper.toDto(tOrderEntity);
        orderDto.setBenefitsStatus(tOrderEntity.getBenefitsStatus());
        return Response.ok(orderDto);
    }


    @Override
    public Response<TOrderDto> saveOrder(String userCode, ProductDto product) {

        TOrderEntity order = new TOrderEntity();
        order.setUserCode(userCode);
        order.setStatus(OrderStatus.INIT.getStatus());
        order.setPayableAmount(product.getPrice());
        order.setProductCode(product.getProductCode());
        order.setProductType(product.getProductType());
        order.setBenefitsStatus(BenefitsStatus.INIT.getStatus());
        order.setAppCode(product.getAppCode());
        Snowflake snowflake = IdUtil.createSnowflake(1, 1);
        long id = snowflake.nextId();
        order.setOrderNo(String.valueOf(id));
        tOrderDao.insert(order);

        TOrderDto tOrderDto = mapper.toDto(order);
        return Response.ok(tOrderDto);
    }

    @Resource
    ProductDao productDao;
    @Resource
    GoogleSubScriptionsBasicPayImpl googleSubScriptionsBasicPay;


    @Override
    public Response<TOrderDto> saveOrder(AddOrderReq req) {
        if (Objects.isNull(req)) {
            return Response.error("The parameter should not be empty!");
        }
        if (StringUtils.isEmpty(req.getUserCode())) {
            return Response.error("The userCode should not be empty!");
        }
        final ProductDto productDto = req.getProductDto();
        if (Objects.isNull(productDto) || StringUtils.isEmpty(productDto.getProductCode())) {
            return Response.error("The productCode should not be empty!");
        }

        final Integer purchaseType = productDto.getPurchaseType();
        if (purchaseType == null) {
            final ProductEntity product = productDao.selectByProductCode(productDto.getProductCode());
            if (Objects.nonNull(product)) {
                productDto.setPurchaseType(product.getPurchaseType());
                productDto.setProductConfig(product.getProductConfig());
                productDto.setAppCode(product.getAppCode());
            }
        }

        String existsPurchaseToken = null;
        if (Objects.nonNull(purchaseType) && PurchaseType.SUBSCRIPTION_PRODUCT.getType().equals(purchaseType)) {
            // 查询最近订阅成功的一笔订单
            TOrderEntity oldOrder = tOrderDao.selectPaidOrderByPurchase(req.getUserCode(), PurchaseType.SUBSCRIPTION_PRODUCT.getType());
            if (Objects.nonNull(oldOrder)) {
                if (StringUtils.isNotEmpty(oldOrder.getPurchaseToken())) {
                    existsPurchaseToken = oldOrder.getPurchaseToken();

                    // 检查上笔订阅是否有效
                    final String purchaseResult = googleSubScriptionsBasicPay.queryExtentInfo(buildRepayRequest(productDto, existsPurchaseToken));
                    if (StringUtils.isNotEmpty(purchaseResult)) {
                        final JSONObject purchaseResultJson = JSONObject.parseObject(purchaseResult);

                        /**
                         * google pay 订阅状态
                         * SUBSCRIPTION_STATE_UNSPECIFIED	未指定订阅状态。
                         * SUBSCRIPTION_STATE_PENDING	已创建订阅，但在注册期间正在等待付款。在此状态下，所有商品均正在等待付款。
                         * SUBSCRIPTION_STATE_ACTIVE	订阅处于有效状态。- (1) 如果订阅是自动续订型方案，则至少有一项是自动续订状态并且未过期。- (2) 如果订阅是预付费方案，至少有一项不会过期。
                         * SUBSCRIPTION_STATE_PAUSED	订阅已暂停。只有在订阅是自动续订型方案时，才会显示该状态。在此状态下，所有商品均处于暂停状态。
                         * SUBSCRIPTION_STATE_IN_GRACE_PERIOD	订阅处于宽限期。只有在订阅是自动续订型方案时，才会显示该状态。在此状态下，所有商品均处于宽限期。
                         * SUBSCRIPTION_STATE_ON_HOLD	订阅已暂停（已暂停）。只有在订阅是自动续订型方案时，才会显示该状态。在此状态下，所有商品均处于保全状态。
                         * SUBSCRIPTION_STATE_CANCELED	订阅已取消，但尚未过期。只有在订阅是自动续订型方案时，才会显示该状态。所有商品的 autoRenewEnabled 都设为 false。
                         * SUBSCRIPTION_STATE_EXPIRED	订阅已过期。所有内容的过期时间都是过去的时间。
                         * @author linqu
                         */
                        if (purchaseResultJson.getString("subscriptionState").equalsIgnoreCase("SUBSCRIPTION_STATE_EXPIRED")
                        || purchaseResultJson.getString("subscriptionState").equalsIgnoreCase("SUBSCRIPTION_STATE_CANCELED")
                                || purchaseResultJson.getString("subscriptionState").equalsIgnoreCase("SUBSCRIPTION_STATE_ON_HOLD")
                                || purchaseResultJson.getString("subscriptionState").equalsIgnoreCase("SUBSCRIPTION_STATE_IN_GRACE_PERIOD")) {
                            // 弃用无效的订阅，保证新订阅的创建
                            existsPurchaseToken = null;
                        }
                    }
                }
            }
        }


        TOrderEntity order = new TOrderEntity();
        order.setUserCode(req.getUserCode());
        order.setStatus(OrderStatus.INIT.getStatus());
        order.setPayableAmount(productDto.getPrice());
        order.setProductCode(productDto.getProductCode());
        order.setProductType(productDto.getProductType());
        order.setPurchaseType(productDto.getPurchaseType());
        order.setPurchaseToken(req.getPurchaseToken());
        order.setBenefitsStatus(BenefitsStatus.INIT.getStatus());
        order.setAppCode(productDto.getAppCode());
        order.setModelUserCode(req.getModelUserCode());
        Snowflake snowflake = IdUtil.createSnowflake(1, 1);
        long id = snowflake.nextId();
        order.setOrderNo(String.valueOf(id));
        tOrderDao.insert(order);

        // 添加订单日志
        addOrderLog(order, req.getAppVersionName());

        TOrderDto tOrderDto = mapper.toDto(order);
        tOrderDto.setLatestPaidOrderPurchaseToken(existsPurchaseToken);
        return Response.ok(tOrderDto);
    }

    private void addOrderLog(TOrderEntity order, String appVersion) {

        try {
            log.info("addOrderLog, order:{}", JSONObject.toJSONString(order));
            TOrderLogEntity orderLogEntity = new TOrderLogEntity();
            BeanUtils.copyProperties(order, orderLogEntity);
            orderLogEntity.setAppVersion(appVersion);
            orderLogDao.insert(orderLogEntity);
        } catch (BeansException e) {
            log.error("addOrderLogError, order:{}", JSONObject.toJSONString(order), e);
        }
    }

    /**
     * 续订成功
     * @param latestOrderNo 上一笔订阅订单号
     * @param newOrderId 续订成功后googlepay返回的订单号
     * @param purchaseToken 支付token
     * @return
     */
    @Override
    public Response<TOrderDto> subscriptionOrder(String latestOrderNo, String newOrderId, String purchaseToken) {
        if (StringUtils.isEmpty(latestOrderNo)) {
            return Response.error("The parameter [latestOrderNo] should not be empty");
        }
        if (StringUtils.isEmpty(newOrderId)) {
            return Response.error("The parameter [newOrderId] should not be empty");
        }
        if (StringUtils.isEmpty(purchaseToken)) {
            return Response.error("The parameter [purchaseToken] should not be empty");
        }
        final TOrderEntity oldOrder = tOrderDao.queryByOrderNo(latestOrderNo);

        final ProductEntity product = productDao.selectByProductCode(oldOrder.getProductCode());

        TOrderEntity newOrder = new TOrderEntity();
        Snowflake snowflake = IdUtil.createSnowflake(1, 1);
        BeanUtils.copyProperties(oldOrder, newOrder);
        newOrder.setOrderId(newOrderId);
        newOrder.setOrderNo(String.valueOf(snowflake.nextId()));
        newOrder.setStatus(OrderStatus.PAID.getStatus());
        newOrder.setBenefitsStatus(BenefitsStatus.INIT.getStatus());
        if (product != null && product.getProductCategory() != ProductCategory.MEMBER.getCode()) {
            newOrder.setPayableAmount(product.getOriginalPrice() == null ? product.getPrice() : product.getOriginalPrice());
        }
        tOrderDao.insert(newOrder);
        return Response.ok(mapper.toDto(newOrder));
    }

    private RepayRequest buildRepayRequest(ProductDto productDto, String purchaseToken) {
        final String productConfig = productDto.getProductConfig();
        final JSONObject parseObject = JSONObject.parseObject(productConfig);

        JSONObject ext = new JSONObject();
        ext.put("packageName", parseObject.getString("packageName"));
        ext.put("productId", parseObject.getString("purchaseProductName"));
        ext.put("purchaseToken",purchaseToken);

        return RepayRequest.builder()
                .payGateway(PayGatewayEnum.GOOGLE_PAY_SUBSCRIPTIONS.getCode())
                .payType(String.valueOf(PayTypeEnum.REPAY.getCode()))
                .payExt(ext.toJSONString()).build();
    }

    @Override
    public Response<String> updateOrder(TOrderDto tOrderDto) {
        TOrderEntity tOrderEntity = new TOrderEntity();
        if (Objects.nonNull(tOrderDto.getStatus())) {
            tOrderEntity.setStatus(tOrderDto.getStatus());
        }
        tOrderEntity.setOrderNo(tOrderDto.getOrderNo());
        if (StringUtils.isNotEmpty(tOrderDto.getOrderId())) {
            tOrderEntity.setOrderId(tOrderDto.getOrderId());
        }
        if (Objects.nonNull(tOrderDto.getPaidAmount())) {
            tOrderEntity.setPaidAmount(tOrderDto.getPaidAmount());
        }
        if (StringUtils.isNotEmpty(tOrderDto.getPurchaseToken())) {
            tOrderEntity.setPurchaseToken(tOrderDto.getPurchaseToken());
        }
        if (Objects.nonNull(tOrderDto.getBenefitsStatus())) {
            tOrderEntity.setBenefitsStatus(tOrderDto.getBenefitsStatus());
        }
        if (StringUtils.isNotEmpty(tOrderDto.getStartTime())) {
            tOrderEntity.setStartDate(tOrderDto.getStartDate());
        }
        if (StringUtils.isNotEmpty(tOrderDto.getExpiryTime())) {
            tOrderEntity.setExpiryTime(tOrderDto.getExpiryTime());
        }

        int i = tOrderDao.updateByOrderNo(tOrderEntity);
        if (i > 0) {
            return Response.ok();
        } else {
            return Response.error(TradeResultStatus.ORDER_UPDATE_FAILED);
        }
    }

    /**
     * c
     * @param userCode
     * @return
     */
    @Override
    public Response<TOrderDto> queryLatestSubscriptionsOrder(String userCode) {
        TOrderEntity oldOrder = tOrderDao.selectPaidOrderByPurchase(userCode, PurchaseType.SUBSCRIPTION_PRODUCT.getType());
        return Response.ok(mapper.toDto(oldOrder));
    }

    @Override
    public Response<List<TOrderDto>> listPaidOrder() {
        List<TOrderEntity> orderList = tOrderDao.listPaidOrder();
        if (CollectionUtils.isEmpty(orderList)) {
            return Response.ok();
        }
        final List<TOrderDto> orderDtoList = orderList.parallelStream().map(o -> {
            TOrderDto dto = new TOrderDto();
            BeanUtils.copyProperties(o, dto);
            dto.setPaidDate(DateUtil.getDate(o.getGmtCreate(), DatePattern.NORM_DATE_PATTERN));
            return  dto;
        }).collect(Collectors.toList());

        return Response.ok(orderDtoList);
    }
}
